package net.xumf.service.master.impl;

import com.google.common.collect.Lists;
import net.xumf.dao.master.SystemModuleRepository;
import net.xumf.domain.master.SystemModule;
import net.xumf.domain.master.SystemPermission;
import net.xumf.domain.master.SystemRole;
import net.xumf.domain.master.SystemUser;
import net.xumf.service.master.SystemModuleService;
import net.xumf.service.master.SystemPermissionService;
import net.xumf.service.master.SystemRoleService;
import net.xumf.support.common.BaseServiceImpl;
import net.xumf.support.consts.Constants;
import net.xumf.support.converter.PageConverter;
import net.xumf.support.converter.SystemModuleConverter;
import net.xumf.support.enums.CodeEnum;
import net.xumf.support.enums.SwitchStatus;
import net.xumf.support.exception.NotFoundDataRowInfoException;
import net.xumf.support.model.dto.ModuleModifyDTO;
import net.xumf.support.model.dto.PageDTO;
import net.xumf.support.model.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SystemModuleServiceImpl extends BaseServiceImpl<SystemModuleRepository, SystemModule, Integer> implements SystemModuleService {

    @Autowired
    private SystemRoleService systemRoleService;

    @Autowired
    private SystemPermissionService permissionService;

    @Override
    public PageVO getSystemModulesByParentIdAndPage(Integer parentId, PageDTO pageDTO) {

        Pageable pageable = PageConverter.pageVOToPageable(pageDTO);
        Page<SystemModule> systemModulePage = repository.findByParentId(parentId, pageable);
        return PageConverter.pageToPageDTO(systemModulePage);
    }

    @Override
    public List<? extends ModuleBaseVO> getSystemModulesByParentId(Integer parentId) {

        List<SystemModule> moduleList = repository.findByParentId(parentId);
        List<TreeVO> treeVOList = SystemModuleConverter.toModuleTreeVOList(moduleList);
        return make(treeVOList, parentId);
    }

    @Override
    public PageVO getSystemModules(PageDTO pageDTO) {
        Pageable pageable = PageConverter.pageVOToPageable(pageDTO);
        Page<SystemModule> systemModulePage = repository.findAll(pageable);
        return PageConverter.pageToPageDTO(systemModulePage);
    }

    @Override
    @Transactional
    public void remove(Integer pojoId) {
        // 查找模块
        repository.findById(pojoId).ifPresent(o -> {
            // 获取删除模块的所有子模块
            List<Integer> moduleIdList = Lists.newArrayList(getAll()).stream()
                    .filter(m -> m.getParentId().equals(pojoId))
                    .map(SystemModule::getModuleId).collect(Collectors.toList());
            moduleIdList.add(pojoId);
            // 删除模块相关的权限
            permissionService.removeByModuleIdIn(moduleIdList);
            // 删除模块及其子模块
            repository.deleteByModuleIdOrParentId(pojoId);
            // 如果父模块不为顶级模块
            if (Constants.Normal.ROOT_ID != o.getParentId()) {
                long count = repository.countByParentId(o.getParentId());
                // 如果子模块为0
                if (count == 0) {
                    // 设置hasChild 为false
                    repository.findById(o.getParentId()).ifPresent(p -> {
                        p.setHasChild(false);
                        repository.save(p);
                    });
                }
            }
        });
    }

    @Override
    public <S extends SystemModule> SystemModule add(S pojo) {
        SystemModule systemModule = new SystemModule();
        BeanUtils.copyProperties(pojo, systemModule, "hasChild", "linkType", "target", "params");
        systemModule.setHasChild(false);
        systemModule.setLinkType(0);
        systemModule.setTarget("_self");
        // 如果父模块不为根
        SystemModule rs;
        if (pojo.getParentId() == Constants.Normal.ROOT_ID) {
            systemModule = repository.save(systemModule);
            systemModule.setPath(systemModule.getModuleId().toString());
            rs = repository.save(systemModule);
        } else {
            Optional<SystemModule> optionalModule = repository.findById(pojo.getParentId());
            SystemModule parentSystemModule = optionalModule
                    .orElseThrow(() -> new NotFoundDataRowInfoException(CodeEnum.MODIFY_NOT_FOUND_ROW_ERROR));
            systemModule.setCode(parentSystemModule.getCode() + '.' + systemModule.getCode());
            // 如果之前不存在子模块，更新父模块状态，否则不操作
            if (!parentSystemModule.getHasChild()) {
                parentSystemModule.setHasChild(true);
                repository.save(parentSystemModule);
            }
            // 添加模块
            systemModule = repository.save(systemModule);
            // 更新path
            systemModule.setPath(
                    parentSystemModule.getModuleId().toString() + ',' + systemModule.getModuleId()
            );
            rs = repository.save(systemModule);
        }
        return rs;
    }


    @Override
    public List<SystemModule> getModuleOfCurrentUser() {
        List<SystemModule> systemModules;
        // todo: 1 ShiroUtil.isSuperAdmin()
        if (true) {
            systemModules = Lists.newArrayList(repository.findAll());
        } else {
            // todo: 1
            SystemUser user = null;
            // 获取用户拥有角色的所有模块
            List<String> moduleList = systemRoleService.getByRoleIdIn(user.getRoles()).stream()
                    .map(SystemRole::getModules).collect(Collectors.toList());
            systemModules = getByModuleIdIn(moduleList);
        }
        return systemModules;
    }

    @Override
    public List<ZtreeVO> getZtreeVO(Integer roleId) {

        // 获取角色拥有的权限
        String permissionStr = systemRoleService.getById(roleId)
                .map(SystemRole::getPermissions).orElse("");
        List<Integer> permissionIdList;
        if (StringUtils.isEmpty(permissionStr)) {
            permissionIdList = new ArrayList<>();
        } else {
            permissionIdList = Arrays.stream(permissionStr.split(","))
                    .map(Integer::parseInt)
                    .collect(Collectors.toList());
        }
        // 用户相关模块
        List<SystemModule> moduleList = Lists.newArrayList(getAll());
        // 所有权限
        List<SystemPermission> permissionList = Lists.newArrayList(permissionService.getAll());
        // 处理数据为ztree格式  // 设置moduleId 为负数便于区分模块与权限
        List<ZtreeVO> ztreeVOListOne = moduleList.stream().map(o -> ZtreeVO.builder()
                .id(-o.getModuleId())
                .pId(-o.getParentId())
                .name(o.getName())
                .open(o.getParentId() == 0 ? true : null)
                .build()).collect(Collectors.toList());
        List<ZtreeVO> ztreeVOListTwo = permissionList.stream().map(o -> ZtreeVO.builder()
                .id(o.getPermissionId())
                .pId(-o.getModuleId())
                .checked(permissionIdList.contains(o.getPermissionId()) ? true : null)
                .name(o.getName())
                .build()).collect(Collectors.toList());
        ztreeVOListOne.addAll(ztreeVOListTwo);
        return ztreeVOListOne;
    }

    @Override
    public List<SystemModule> getByModuleIdIn(String moduleIdsString) {
        if (StringUtils.isEmpty(moduleIdsString)) {
            return Lists.newArrayList();
        }
        List<Integer> moduleIds = Arrays.stream(moduleIdsString.split(","))
                .map(Integer::parseInt).collect(Collectors.toList());
        return repository.findByModuleIdIn(moduleIds);
    }

    @Override
    public List<SystemModule> getByModuleIdIn(List<String> moduleIdsStrings) {
        Optional<String> permissionIdsString = moduleIdsStrings.stream()
                .filter(o -> !StringUtils.isEmpty(o)).reduce((a, b) -> a + ',' + b);
        return getByModuleIdIn(permissionIdsString.orElse(""));
    }

    @Override
    public List<? extends ModuleBaseVO> getWebPageMenuModuleBy() {

        List<SystemModule> systemModules = getModuleOfCurrentUser();
        List<ModuleMenuVO> moduleMenuVOList = systemModules.stream()
                .filter(o -> o.getStatus() == SwitchStatus.ENABLE.getCode())
                .map(o -> {
                    ModuleMenuVO moduleMenuVO = new ModuleMenuVO();
                    BeanUtils.copyProperties(o, moduleMenuVO);
                    moduleMenuVO.setLabel(o.getName());
                    return moduleMenuVO;
                }).collect(Collectors.toList());
        return make(moduleMenuVOList, Constants.Normal.ROOT_ID);
    }

    public List<? extends ModuleBaseVO> getWebPageTreeModuleBy() {

        List<SystemModule> systemModules = getModuleOfCurrentUser();
        List<TreeVO> treeVOList = SystemModuleConverter.toModuleTreeVOList(systemModules);
        return make(treeVOList, Constants.Normal.ROOT_ID);
    }

    @Override
    public List<? extends ModuleBaseVO> getModuleAndRoleForTree() {

        // 用户相关模块
        List<SystemModule> moduleList = Lists.newArrayList(getAll());
        // 所有权限
        List<SystemPermission> permissionList = Lists.newArrayList(permissionService.getAll());
        // 处理数据为ztree格式  // 设置moduleId 为负数便于区分模块与权限
        List<TreeVO> treeVOListOne = moduleList.stream().map(o -> {
            TreeVO treeVO = new TreeVO();
            treeVO.setModuleId(-o.getModuleId());
            treeVO.setParentId(-o.getParentId());
            treeVO.setSequence(o.getSequence());
            treeVO.setCode(o.getCode());
            treeVO.setHasChild(o.getHasChild());
            treeVO.setLeaf(o.getHasChild());
            treeVO.setLabel(o.getName());
            return treeVO;
        }).collect(Collectors.toList());
        List<TreeVO> treeVOListTwo = permissionList.stream().map(o -> {
            TreeVO treeVO = new TreeVO();
            treeVO.setLabel(o.getName());
            treeVO.setModuleId(o.getPermissionId());
            treeVO.setParentId(-o.getModuleId());
            treeVO.setSequence(o.getSequence());
            treeVO.setCode(o.getCode());
            treeVO.setHasChild(false);
            treeVO.setLeaf(false);
            return treeVO;
        }).collect(Collectors.toList());
        treeVOListOne.addAll(treeVOListTwo);
        return make(treeVOListOne, Constants.Normal.ROOT_ID);
    }

    @Override
    public List<? extends ModuleBaseVO> getModuleForTable() {

        Iterable<SystemModule> moduleList = repository.findAll();
        List<ModuleTableVO> moduleMenuVOList = Lists.newArrayList(moduleList).stream().map(o -> {
            ModuleTableVO moduleMenuVO = new ModuleTableVO();
            BeanUtils.copyProperties(o, moduleMenuVO);
            moduleMenuVO.setHasChildren(o.getHasChild());
            return moduleMenuVO;
        }).collect(Collectors.toList());
        return make(moduleMenuVOList, Constants.Normal.ROOT_ID);
    }

    @Override
    public List<? extends ModuleBaseVO> getModuleForTableByParentId(Integer parentId) {
        List<SystemModule> moduleList = repository.findByParentId(parentId);
        List<ModuleTableVO> moduleMenuVOList = moduleList.stream().map(o -> {
            ModuleTableVO moduleMenuVO = new ModuleTableVO();
            BeanUtils.copyProperties(o, moduleMenuVO);
            moduleMenuVO.setHasChildren(o.getHasChild());
            return moduleMenuVO;
        }).collect(Collectors.toList());
        return make(moduleMenuVOList, parentId);
    }

    /**
     * 构造前端所需格式
     *
     * @param moduleBaseVOS {@link ModuleBaseVO}
     * @param moduleId      模块id（0为顶级菜单）
     * @return {@link ModuleBaseVO}
     */
    private List<? extends ModuleBaseVO> make(List<? extends ModuleBaseVO> moduleBaseVOS, Integer moduleId) {
        List<ModuleBaseVO> subMenu = new ArrayList<>();
        for (ModuleBaseVO moduleBaseVO :
                moduleBaseVOS) {
            if (moduleId == moduleBaseVO.getParentId()) {
                subMenu.add(moduleBaseVO);
                List<? extends ModuleBaseVO> childList = make(moduleBaseVOS, moduleBaseVO.getModuleId());
                if (CollectionUtils.isEmpty(childList) && childList.size() == 0) {
//                    moduleBaseVO.setHasChild(false);
                } else {
                    moduleBaseVO.setHasChild(true);
                    moduleBaseVO.setChildren(childList);
                }
            }
        }
        return subMenu.stream().sorted(Comparator.comparing(ModuleBaseVO::getSequence))
                .collect(Collectors.toList());
    }

}
